
#include <faker/launcher/App.h>
#include <faker/render/System.h>

using namespace Faker;

namespace
{
    Faker::Scene scene;

    Faker::Render::System renderSystem;

    Gut::Shader shader;
    Math::Transform transform;
    Math::Camera camera;
    Gut::UniformBuffer passBuffer,objBuffer, matBuffer;
    Gut::MeshIndice mesh;

    struct PassData
    {
        glm::mat4 proj,view;
        glm::vec3 camPos;
        float pad;
        
    };
    struct ObjData
    {
        glm::mat4 world, normalMatrix;
    };
    struct MatData
    {   
        glm::vec4 color;
    };

    PassData passData;
    ObjData objData;
    MatData matData;
    
};

bool Launcher::App::Create(const GLFWConfig &config)
{
    if (!BaseApp::Create(config))
    {
        return false;
    }

    FK_LOGI("Create Launcher app (edit mode )");
    shader.CreateFromFilePath("/home/fanbangzhen/source/ls_app/shader/3d.vert", "/home/fanbangzhen/source/ls_app/shader/singleColor.frag");

    camera.SetPosition(glm::vec3(5.0f));
    camera.LookAt(glm::vec3(0.0f), Math::Transform::Yup());
    camera.aspect = GetAspect();
    camera.fovy = 45.0f;
    camera.nFar = 1000.0f;
    camera.nNear = 0.1f;

    passBuffer.CreateFrom<PassData>(0);
    objBuffer.CreateFrom<ObjData>(1);
    matBuffer.CreateFrom<MatData>(2);

    auto cubeMeshData = Math::Geometry::CreateBox<Faker::Basic::VertexPosNormalTex, unsigned int>();
    mesh.CreateVertexIndiceInputLayout<Faker::Basic::VertexPosNormalTex, unsigned int>(cubeMeshData.vertexVec, cubeMeshData.indexVec);

    return true;
}

void Launcher::App::OnFrameRender()
{
    renderSystem.RenderFrame(scene);

    glViewport(0, 0, this->state.mClientWidth, state.mClientHeight);

    glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shader.Use();
    shader.Bind("PassBuffer", 0);
    shader.Bind("ObjBuffer", 1);
    shader.Bind("MatBuffer", 2);

    passData.proj = camera.GetProjection();
    passData.view = camera.GetViewMatrix();
    passData.camPos = camera.position;

    passBuffer.Upload(passData);

    objData.world = transform.GetWorld();
    objData.normalMatrix = glm::transpose(glm::inverse(objData.world));

    objBuffer.Upload(objData);

    matData.color = glm::vec4(0.5f, 1.0f, 0.5f, 1.0f);
    matBuffer.Upload(matData);

    mesh.DrawElements();
}

void Faker::Launcher::App::OnFrameBufferSize(int width, int height)
{
    BaseApp::OnFrameBufferSize(width, height);
    camera.SetAspect(GetAspect());

}
